import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;

import org.rsbot.event.events.ServerMessageEvent;
import org.rsbot.event.listeners.PaintListener;
import org.rsbot.event.listeners.ServerMessageListener;
import org.rsbot.script.Script;
import org.rsbot.script.ScriptManifest;
import org.rsbot.script.wrappers.*;
import org.rsbot.script.methods.*;

@ScriptManifest(authors = { "Rawr" }, name = "Rawr Fletch", keywords = "Fletching", 
	version = 1.2, description =  "The best Fletching script out there.")
	
public class RawrFletch extends Script implements PaintListener, ServerMessageListener {
	RunAntiBan antiBan;
	Thread t;
	public String state = "Loading", method;
	public int amountStrung = 0, amountFletched = 0;
	public int knife, logs, longbow_unstrung, longbow_strung;
	public int normal_knife = 946,
	clay_knife = 14111;
	public int bowstring = 1777;
	public int willow_logs = 1519,
	maple_logs = 1517,
	yew_logs = 1515,
	magic_logs = 1513;
	public int willow_longbow_unstrung = 58,
	maple_longbow_unstrung = 62,
	yew_longbow_unstrung = 66,
	magic_longbow_unstrung = 70;
	public int yew_longbow_strung = 855,
	magic_longbow_strung = 859;
	public long startTime = System.currentTimeMillis(), waitTimer = System.currentTimeMillis();
	public int gainedXp = 0, startXp = 0, startLvl, currentLvl, lvlsGained, xpToLvl, percent;
	BufferedImage normal = null;
	BufferedImage clicked = null;
	
	public boolean onStart() {
		log.info(":-:-: Loading data for Rawr Fletch:-:-:");
		log.info("Please wait...");
		sleep(random(500, 800));
		
		try {
			final URL cursorURL = new URL("http://imgur.com/i7nMG.png");
			final URL cursor80URL = new URL("http://imgur.com/8k9op.png");
			normal = ImageIO.read(cursorURL);
			clicked = ImageIO.read(cursor80URL);
		} catch (MalformedURLException e) {
			log.info("Unable to buffer cursor.");
		} catch (IOException e) {
			log.info("Unable to open cursor image.");
		}
		
		antiBan = new RunAntiBan();
		t = new Thread(antiBan);
		if (!t.isAlive()) {
			t.start();
		}
		startTime = System.currentTimeMillis();
		startLvl = skills.getCurrentLevel(Skills.FLETCHING);
		gainedXp = skills.getCurrentExp(Skills.FLETCHING);
		
		if (game.isLoggedIn()) {
			if (inventory.contains(bowstring)) {
				method = "Stringing";
				if (inventory.contains(yew_longbow_unstrung)) {
					longbow_unstrung = yew_longbow_unstrung;
					longbow_strung = yew_longbow_strung;
				}
				if (inventory.contains(magic_longbow_unstrung)) {
					longbow_unstrung = magic_longbow_unstrung;
					longbow_strung = magic_longbow_strung;
				}
			} else {
				method = "Fletching";
				if (inventory.contains(normal_knife)) {
					knife = normal_knife;
				}
				if (inventory.contains(clay_knife)) {
					knife = clay_knife;
				}
				if (inventory.contains(willow_logs)) {
					logs = willow_logs;
					longbow_unstrung = willow_longbow_unstrung;
				}
				if (inventory.contains(maple_logs)) {
					logs = maple_logs;
					longbow_unstrung = maple_longbow_unstrung;
				}
				if (inventory.contains(yew_logs)) {
					logs = yew_logs;
					longbow_unstrung = yew_longbow_unstrung;
				}
				if (inventory.contains(magic_logs)) {
					logs = magic_logs;
					longbow_unstrung = magic_longbow_unstrung;
				}
			}
		} else {
			log.info("Not logged in.");
			return false;
		}
		
		log.info("Setting Camera & Mouse Speed.");
		camera.setPitch(true);
		mouse.setSpeed(random(7, 8));
		return true;
	}
	
	public Point mouse() {
		return mouse.getLocation();
	}
	
	public boolean withdraw(int itemID, int amount) {
		String s = amount + "";
		if (bank.isOpen()) {
			if (amount > 0) {
				if (!bank.getItem(itemID).doAction(s)) {
					if (bank.getItem(itemID).doAction("X")) {
						sleep(random(2000, 2500));
						sleep(random(100, 200));
						keyboard.sendText(s, false);
						sleep(random(800, 1000));
						keyboard.sendText("", true);
						return true;
					}
					return true;
				}
			} else {
				return bank.getItem(itemID).doAction("All");
			}
		}
		return false;
	}
	
	@Override
		public int loop() {
		//---------- Wrappers -----------
		RSComponent stringIface = interfaces.getComponent(905, 14);
		RSComponent fletchIface = interfaces.getComponent(905, 15);
		//-------- End Wrappers ---------
		//Stringing
		if (method.equals("Stringing")) {
			if (inventory.contains(longbow_unstrung) && inventory.contains(bowstring)
				&& (System.currentTimeMillis() - waitTimer) >= 1500
				&& !stringIface.isValid() && !bank.isOpen()) {
				RSItem BowString = inventory.getItem(bowstring);
				RSItem LongbowUnstrung = inventory.getItem(longbow_unstrung);
				state = "Trying to string longbows...";
				if (inventory.isItemSelected()) {
					BowString.doClick(true);
					sleep(random(200, 300));
					if (mouse().x < 217 || mouse().x > 299 || mouse().y < 393 || mouse().y > 456) {
						mouse.move(random(220, 290), random(400, 450));
						sleep(random(500, 600));
					}
				} else {
					LongbowUnstrung.doClick(true);
					sleep(random(400, 600));
				}
			}
			if (stringIface.isValid()) {
				state = "Trying to string longbows...";
				stringIface.doClick(true);
				sleep(1500);
			}
			if (!inventory.contains(longbow_unstrung) && !bank.isOpen() 
				|| !inventory.contains(bowstring) && !bank.isOpen()) {
				state = "Opening bank...";
				bank.open();
			}
			if (!inventory.contains(longbow_unstrung) && bank.isOpen() 
				|| !inventory.contains(bowstring) && bank.isOpen()) {
				state = "Banking...";
				if (inventory.contains(longbow_strung)) {
					bank.depositAll();
					sleep(random(1000, 1100));
				}
				if (!inventory.contains(longbow_strung) && 
					inventory.getCount(longbow_unstrung) != 14) {
					withdraw(longbow_unstrung, 14);
					sleep(random(1000, 1100));
				} else {
					bank.depositAll();
				}
				if (!inventory.contains(longbow_strung) && 
					inventory.getCount(bowstring) != 14) {
					withdraw(bowstring, 14);
					sleep(random(900, 1000));
				} else {
					bank.depositAll();
				}
			}
			if (inventory.getCount(longbow_unstrung) == 14 && inventory.getCount(bowstring) == 14
				&& bank.isOpen()) {
				bank.close();
			}
			if (players.getMyPlayer().getAnimation() != -1) {
				state = "Stringing bows...";
				mouse.moveOffScreen();
				waitTimer = System.currentTimeMillis();				
			}
		}
		if (method.equals("Fletching")) {
			if (inventory.contains(knife) && inventory.contains(logs)
				&& (System.currentTimeMillis() - waitTimer) >= 1500
				&& !fletchIface.isValid() && !bank.isOpen()) {
				RSItem Knife = inventory.getItem(knife);
				RSItem Logs = inventory.getItem(logs);
				state = "Trying to fletch longbows...";
				if (inventory.isItemSelected()) {
					Logs.doClick(true);
					sleep(random(200, 300));
					if (mouse().x < 262 || mouse().x > 350 || mouse().y < 393 || mouse().y > 456) {
						mouse.move(random(270, 340), random(400, 450));
						sleep(random(500, 600));
					}
				} else {
					Knife.doClick(true);
					sleep(random(400, 600));
				}
			}
			if (fletchIface.isValid()) {
				state = "Trying to fletch longbows...";
				fletchIface.doClick(true);
				sleep(1500);
			}
			if (!inventory.contains(logs) && !bank.isOpen()) {
				state = "Opening bank...";
				bank.open();
			}
			if (!inventory.contains(logs) && bank.isOpen()) {
				state = "Banking...";
				if (inventory.contains(longbow_unstrung)) {
					bank.depositAllExcept(knife);
					sleep(random(1700, 1800));
				}
				if (!inventory.contains(longbow_unstrung) && !inventory.contains(logs)) {
					bank.withdraw(logs, 0);
					sleep(random(900, 1000));
				}
			}
			if (inventory.contains(logs) && bank.isOpen()) {
				bank.close();
			}
			if (players.getMyPlayer().getAnimation() != -1) {
				state = "Fletching bows...";
				mouse.moveOffScreen();
				waitTimer = System.currentTimeMillis();				
			}
		}
		return 100;
	}
	
	public void serverMessageRecieved(ServerMessageEvent e) {
		String msg = e.getMessage();
		if (msg.contains("shortbow") || msg.contains("longbow")) amountFletched++;
		if (msg.contains("string")) amountStrung++;
	}
	
	public void onFinish() {
		antiBan.stopThread = true;
		long millis = System.currentTimeMillis() - startTime;
		long hours = millis / (1000 * 60 * 60);
		millis -= hours * (1000 * 60 * 60);
		long minutes = millis / (1000 * 60);
		millis -= minutes * (1000 * 60);
		long seconds = millis / 1000;
		gainedXp = skills.getCurrentExp(Skills.FLETCHING) - startXp;
		currentLvl = skills.getCurrentLevel(Skills.FLETCHING);
		lvlsGained = currentLvl - startLvl;
		log.info("Statistics - ");
		log.info("Script ran for: " + hours + ":" + minutes + ":" + seconds + ".");
		log.info("Ending Fletching level: " + currentLvl + " || Levels gained: " + lvlsGained + ".");
		log.info("Total XP gained: " + gainedXp + ".");
	}
	
	public void drawMouse(final Graphics g) {
		if (normal != null) {
			final double mouseX = mouse.getLocation().getX() - 8,
			mouseY = mouse.getLocation().getY() - 8;
			final double mousePressX = mouse.getPressLocation().getX() - 8,
			mousePressY = mouse.getPressLocation().getY() - 8;
			if (System.currentTimeMillis() - mouse.getPressTime() < 400) {
				g.drawImage(clicked, (int) mousePressX, (int) mousePressY, null);
			}
			g.drawImage(normal, (int) mouseX, (int) mouseY, null);
		}
	}
	
	public void drawStringShadow(final String text, final int x, final int y, final Graphics g) {
		g.setColor(Color.BLACK);
		g.drawString(text, x + 1, y + 1);
		g.setColor(Color.WHITE);
		g.drawString(text, x, y);
	}
	
	public void onRepaint(Graphics g) {
		if(game.isLoggedIn()) {
			drawMouse(g);
			long millis = System.currentTimeMillis() - startTime;
			long hours = millis / (1000 * 60 * 60);
			millis -= hours * (1000 * 60 * 60);
			long minutes = millis / (1000 * 60);
			millis -= minutes * (1000 * 60);
			long seconds = millis / 1000;
			long runTime = System.currentTimeMillis() - startTime;
			int strungPerHour = 0;
			int fletchedPerHour = 0;
			int xpPerHour = 0;
			if (runTime / 1000 > 0) {
				strungPerHour = (int) (3600000.0 / runTime * amountStrung);
				fletchedPerHour = (int) (3600000.0 / runTime * amountFletched);
				xpPerHour = (int) (3600000.0 / runTime * gainedXp);
			}
			if ( startXp == 0) {
				startXp = skills.getCurrentExp(Skills.FLETCHING);
			}
			gainedXp = skills.getCurrentExp(Skills.FLETCHING) - startXp;
			currentLvl = skills.getCurrentLevel(Skills.FLETCHING);
			xpToLvl = skills.getExpToNextLevel(Skills.FLETCHING);
			percent = skills.getPercentToNextLevel(Skills.FLETCHING);
			lvlsGained = currentLvl - startLvl;
			drawStringShadow("Run Time: " + hours + " : " + minutes + " : " + seconds, 10, 40, g);
			drawStringShadow("State: " + state, 10, 60, g);
			try {
				if (method.equals("Fletching")) {
					drawStringShadow("Fletched: " + amountFletched + " bows ( " + fletchedPerHour + "/hr )", 10, 80, g);
				} else {
					drawStringShadow("Strung: " + amountStrung + " bows ( " + strungPerHour + "/hr )", 10, 80, g);
				}
			} catch(Exception e) { }
			drawStringShadow("Exp Gained: " + gainedXp + " ( " + xpPerHour + "/hr )", 10, 100, g);
			try {
				if (xpPerHour > 0) {
					long sTNL = (xpToLvl) / (xpPerHour / 3600);
					long hTNL = sTNL / (60 * 60);
					sTNL -= hTNL * (60 * 60);
					long mTNL = sTNL / 60;
					sTNL -= mTNL * 60;
					drawStringShadow("Level in: " + hTNL + ":" + mTNL + ":" + sTNL + " ( " + percent + "% )", 10, 120, g);			
				} else {
					drawStringShadow("Level in: 0:0:0 ( " + percent + "% )", 10, 120, g);
				}
			} catch(Exception e) {
				drawStringShadow("Level in: -1:-1:-1 ( " + percent + "% )", 10, 120, g);
			}
			drawStringShadow("Current Lvl: " + currentLvl + " (" + lvlsGained + ")", 10, 140, g);
		}	 
	}
	
	private class RunAntiBan implements Runnable {
		public boolean stopThread;
		
		public void run() {
			while (!stopThread) {
				try {
					if (random(0, 10) == 0) {
						final char[] LR = new char[] { KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT };
						final char[] UD = new char[] { KeyEvent.VK_DOWN, KeyEvent.VK_UP };
						final char[] LRUD = new char[] { KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, KeyEvent.VK_UP, KeyEvent.VK_UP };
						final int random2 = random(0, 2);
						final int random1 = random(0, 2);
						final int random4 = random(0, 4);
						if (random(0, 3) == 0) {
							keyboard.pressKey(LR[random1]);
							sleep(random(100, 400));
							keyboard.pressKey(UD[random2]);
							sleep(random(300, 600));
							keyboard.releaseKey(UD[random2]);
							sleep(random(100, 400));
							keyboard.releaseKey(LR[random1]);
						} else {
							keyboard.pressKey(LRUD[random4]);
							if (random4 > 1) {
								sleep(random(300, 600));
							} else {
								sleep(random(500, 900));
							}
							keyboard.releaseKey(LRUD[random4]);
						}
					} else {
						sleep(random(200, 2000));
					}
				} catch (final Exception e) { e.printStackTrace(); }
			}
		}
	}
}

